home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / misc / emu / msh-156.lha / han / hanlock.c < prev    next >
C/C++ Source or Header  |  1996-12-22  |  24KB  |  925 lines

  1. /*-
  2.  * $Id: hanlock.c,v 1.56 1996/12/22 00:22:33 Rhialto Rel $
  3.  * $Log: hanlock.c,v $
  4.  * Revision 1.56  1996/12/22  00:22:33  Rhialto
  5.  * File locks only updated on disk when last unlocked.
  6.  *
  7.  * Revision 1.55  1993/12/30  23:28:00    Rhialto
  8.  * Freeze for MAXON5.
  9.  * Lots of small changes for LONGNAMES option.
  10.  *
  11.  * Revision 1.54  1993/06/24  05:12:49    Rhialto
  12.  * DICE 2.07.54R.
  13.  *
  14.  * Revision 1.53  92/10/25  02:28:50  Rhialto
  15.  * No real change.
  16.  *
  17.  * Revision 1.52  92/09/06  01:52:30  Rhialto
  18.  * Handle /parentdir via MSParentDir().
  19.  *
  20.  * Revision 1.51  92/04/17  15:37:41  Rhialto
  21.  * Freeze for MAXON.
  22.  *
  23.  * Revision 1.46  91/10/06  18:26:37  Rhialto
  24.  *
  25.  * Freeze for MAXON
  26.  *
  27.  * Revision 1.43  91/09/28  01:41:06  Rhialto
  28.  * Changed to newer syslog stuff.
  29.  * Fix bug that assign always refers to the rootdir.
  30.  *
  31.  * Revision 1.42  91/06/13  23:55:16  Rhialto
  32.  * DICE conversion
  33.  *
  34.  * Revision 1.41  91/06/13  23:37:53  Rhialto
  35.  * Fix MSSetProtect (converted dirs into files) + DICE conversion
  36.  *
  37.  * Revision 1.40  91/03/03  17:53:35  Rhialto
  38.  * Freeze for MAXON
  39.  *
  40.  * Revision 1.33  91/01/24  00:08:27  Rhialto
  41.  * Fix directory-extension bug (only first sector of new cluster
  42.  * was zeroed)
  43.  *
  44.  * Revision 1.32  90/11/23  23:54:18  Rhialto
  45.  * Prepare for syslog
  46.  *
  47.  * Revision 1.31  90/11/10  02:48:38  Rhialto
  48.  * Patch 3a. Introduce disk volume date. Update modification time of
  49.  * directories.
  50.  *
  51.  * Revision 1.30  90/06/04  23:17:18  Rhialto
  52.  * Release 1 Patch 3
  53.  *
  54.  * HANLOCK.C
  55.  *
  56.  * The code for the messydos file system handler
  57.  *
  58.  * The Lock department. Takes care of operations on locks, and consequently,
  59.  * on directories.
  60.  *
  61.  * This code is (C) Copyright 1989-1993 by Olaf Seibert. All rights reserved.
  62.  * May not be used or copied without a licence.
  63. -*/
  64.  
  65. #include "han.h"
  66. #include "dos.h"
  67. #include <string.h>
  68.  
  69. #if HDEBUG
  70. #   include "syslog.h"
  71. #else
  72. #   define    debug(x)
  73. #endif
  74.  
  75. Prototype int CompareNames(struct MsDirEntry *dir, byte *name);
  76. Prototype void NextDirEntry(word *sector, word *offset);
  77. Prototype struct DirEntry *FindNext(struct DirEntry *previous, int createit);
  78. Prototype void PrintDirEntry(struct DirEntry *de);
  79. Prototype struct MSFileLock *MakeLock(struct MSFileLock *parentdir, struct DirEntry *dir, ulong mode);
  80. Prototype struct MSFileLock *MSLock(struct MSFileLock *parentdir, byte *name, ulong mode);
  81. Prototype struct MSFileLock *MSDupLock(struct MSFileLock *fl);
  82. Prototype struct MSFileLock *MSParentDir(struct MSFileLock *fl);
  83. Prototype long MSUnLock(struct MSFileLock *fl);
  84. Prototype void ExamineDirEntry(struct MsDirEntry *msd, struct FileInfoBlock *fib);
  85. Prototype long MSExamine(struct MSFileLock *fl, struct FileInfoBlock *fib);
  86. Prototype long MSExNext(struct MSFileLock *fl, struct FileInfoBlock *fib);
  87. Prototype long MSSetProtect(struct MSFileLock *parentdir, char *name, long mask);
  88. Prototype int CheckLock(struct MSFileLock *lock);
  89. Prototype void WriteDirtyFileLock(struct MSFileLock *fl);
  90. Prototype void WriteFileLock(struct MSFileLock *fl);
  91. Prototype void DirtyFileLock(struct MSFileLock *fl);
  92. Prototype void UpdateFileLock(struct MSFileLock *fl);
  93. Prototype struct LockList *NewLockList(void *cookie);
  94. Prototype void FreeLockList(struct LockList *ll);
  95.  
  96. Prototype struct LockList *LockList;
  97. Prototype struct MSFileLock *RootLock;
  98. Prototype struct MSFileLock *EmptyFileLock;
  99. Prototype const struct DirEntry FakeRootDirEntry;
  100. Prototype const byte DotDot[1 + L_8 + L_3];
  101.  
  102. struct LockList *LockList;    /* List of all locked files we have. Note
  103.                  * this is not the same as all locks we
  104.                  * have */
  105. struct MSFileLock *RootLock;    /* Lock on root directory */
  106. struct MSFileLock *EmptyFileLock;    /* 2nd result of MSLock() */
  107.  
  108. #if LONGNAMES
  109. const struct DirEntry FakeRootDirEntry = {
  110.     {                /* de_Msd */
  111.     0,            /* msd_Time */
  112.     DATE_MIN,        /* msd_Date, 1/1/80 */
  113.     0,            /* msd_Cluster */
  114.     0,            /* msd_Filesize */
  115.     ATTR_VOLUMELABEL,    /* msd_Attributes */
  116.     "Unnamed              " /* msd_Name */
  117.     },
  118.     ROOT_SEC,            /* de_Sector */
  119.     -2                /* de_Offset */
  120. };
  121. #else
  122. const struct DirEntry FakeRootDirEntry = {
  123.     {                /* de_Msd */
  124.     "Unnamed ",             /* msd_Name */
  125.     "   ",                  /* msd_Ext */
  126.     ATTR_VOLUMELABEL,    /* msd_Attributes */
  127.     0,            /* msd_CreationTime */
  128.     DATE_MIN,        /* msd_CreationDate, 1/1/80 */
  129.     {0},            /* msd_Pad1 */
  130.     0,            /* msd_Time */
  131.     DATE_MIN,        /* msd_Date, 1/1/80 */
  132.     0,            /* msd_Cluster */
  133.     0            /* msd_Filesize */
  134.     },
  135.     ROOT_SEC,            /* de_Sector */
  136.     -2                /* de_Offset */
  137. };
  138. #endif
  139. const byte DotDot[1 + L_8 + L_3] = "..          ";
  140.  
  141. /*
  142.  * This routine compares a name in a directory entry with a given name
  143.  */
  144.  
  145. int
  146. CompareNames(dir, name)
  147. struct MsDirEntry *dir;
  148. byte  *name;
  149. {
  150.     if (dir->msd_Name[0] & DIR_DELETED_MASK)
  151.     return CMP_FREE_SLOT;
  152.  
  153.     if (dir->msd_Name[0] == 0)
  154.     return CMP_END_OF_DIR;    /* end of directory */
  155.  
  156.     if (dir->msd_Attributes & ATTR_VOLUMELABEL)
  157.     return CMP_NOT_EQUAL;
  158.  
  159.     if (strncmp(dir->msd_Name, name, L_8 + L_3))
  160.     return CMP_NOT_EQUAL;
  161.  
  162.     if (dir->msd_Attributes & ATTR_DIRECTORY)
  163.     return CMP_OK_DIR;
  164.  
  165.     return CMP_OK_FILE;
  166. }
  167.  
  168. void
  169. NextDirEntry(sector, offset)
  170. word  *sector;
  171. word  *offset;
  172. {
  173.     if ((*offset += MS_DIRENTSIZE) >= Disk.bps) {
  174.     *offset = 0;
  175.     if (*sector >= Disk.datablock) {
  176.         /* Must be subdirectory */
  177.         *sector = NextClusteredSector(*sector);
  178.         debug(("NextClusteredSector: %ld\n", (long)*sector));
  179.     } else {
  180.         if (++*sector >= Disk.datablock) {
  181.         *sector = SEC_EOF;
  182.         }
  183.     }
  184.     }
  185.     /* else no more work needed */
  186. }
  187.  
  188. /*
  189.  * Get the directory entry following the given one. If requested, we make
  190.  * the directory longer.
  191.  */
  192.  
  193. struct DirEntry *
  194. FindNext(previous, createit)
  195. struct DirEntry *previous;
  196. int        createit;
  197. {
  198.     byte       *sector;
  199.     word        prevsec = previous->de_Sector;
  200.  
  201.     NextDirEntry(&previous->de_Sector, &previous->de_Offset);
  202.  
  203.     if (previous->de_Sector == SEC_EOF) {
  204.     error = ERROR_OBJECT_NOT_FOUND;
  205. #if ! READONLY
  206.     if (createit) {
  207.         int         clearblocks;
  208.  
  209.         if (prevsec < Disk.datablock - 1) { /* Should not be necessary */
  210.         previous->de_Sector = prevsec + 1;
  211.         clearblocks = 1;    /* Clear just one root dir block */
  212.         } else if (prevsec >= Disk.datablock) {
  213.         previous->de_Sector = FindFreeSector(prevsec);
  214.         clearblocks = Disk.spc; /* Clear the entire (implied) cluster */
  215.         }
  216.         if (previous->de_Sector != SEC_EOF) {
  217.         for (prevsec = previous->de_Sector; clearblocks; clearblocks--) {
  218.             sector = EmptySec(prevsec);
  219.             setmem(sector, (int) Disk.bps, 0);
  220.             MarkSecDirty(sector);
  221.             FreeSec(sector);
  222.             prevsec++;
  223.         }
  224.  
  225.         /*
  226.          * Just return a clear directory entry
  227.          */
  228.         setmem(&previous->de_Msd, sizeof (previous->de_Msd), 0);
  229.  
  230.         return previous;
  231.         }
  232.     }
  233. #endif
  234.     } else if (sector = ReadSec(previous->de_Sector)) {
  235.     CopyMem(sector + previous->de_Offset, (char *)&previous->de_Msd,
  236.         (long) MS_DIRENTSIZE);
  237.     OtherEndianMsd(&previous->de_Msd);
  238.     FreeSec(sector);
  239.  
  240.     return previous;
  241.     }
  242.     return NULL;
  243. }
  244.  
  245. #if HDEBUG
  246.  
  247. void PrintDirEntry(struct DirEntry *de);
  248.  
  249. void
  250. PrintDirEntry(de)
  251. struct DirEntry *de;
  252. {
  253.     debug(("%ld,%ld ", (long)de->de_Sector, (long)de->de_Offset));
  254. #if LONGNAMES
  255.     debug(("%.21s attr:%lx time:%lx date:%lx start:%lx size:%lx\n",
  256.        de->de_Msd.msd_Name,
  257.        (long)de->de_Msd.msd_Attributes,
  258.        (long)de->de_Msd.msd_Time,
  259.        (long)de->de_Msd.msd_Date,
  260.        (long)de->de_Msd.msd_Cluster,
  261.        (long)de->de_Msd.msd_Filesize
  262.        ));
  263. #else
  264.     debug(("%.8s.%.3s attr:%lx time:%lx date:%lx start:%lx size:%lx\n",
  265.        de->de_Msd.msd_Name,
  266.        de->de_Msd.msd_Ext,
  267.        (long)de->de_Msd.msd_Attributes,
  268.        (long)de->de_Msd.msd_Time,
  269.        (long)de->de_Msd.msd_Date,
  270.        (long)de->de_Msd.msd_Cluster,
  271.        (long)de->de_Msd.msd_Filesize
  272.        ));
  273. #endif
  274. }
  275.  
  276. #endif
  277.  
  278. /*
  279.  * MakeLock makes a struct MSFileLock from a directory entry and the
  280.  * parent directory MSFileLock pointer. It looks if it already has a Lock
  281.  * on it. In that case, it simply increments its reference count, when
  282.  * possible.
  283.  */
  284.  
  285. struct MSFileLock *
  286. MakeLock(parentdir, dir, mode)
  287. struct MSFileLock *parentdir;
  288. struct DirEntry *dir;
  289. ulong        mode;
  290. {
  291.     struct MSFileLock *fl;
  292.     struct MSFileLock *nextfl;
  293.  
  294.     if (mode != EXCLUSIVE_LOCK || (dir->de_Msd.msd_Attributes & ATTR_DIR))
  295.     mode = SHARED_LOCK;
  296.  
  297. #if HDEBUG
  298.     debug(("MakeLock: "));
  299.     PrintDirEntry(dir);
  300. #endif
  301.  
  302.     /*
  303.      * Look through our list to see if we already have it. The criteria
  304.      * for this are: 1. the directory entries are the same or 2. they have
  305.      * the same first cluster and are both directories (which can have
  306.      * multiple directory entries). Sigh.
  307.      */
  308.  
  309.     for (fl = (struct MSFileLock *) LockList->ll_List.mlh_Head;
  310.      nextfl = (struct MSFileLock *) fl->msfl_Node.mln_Succ;
  311.      fl = nextfl) {
  312. #if HDEBUG
  313.     debug(("> "));
  314.     PrintDirEntry((struct DirEntry *)&fl->msfl_Msd);
  315. #endif
  316.     if ((fl->msfl_DirSector == dir->de_Sector &&
  317.          fl->msfl_DirOffset == dir->de_Offset) ||
  318.         (fl->msfl_Msd.msd_Cluster == dir->de_Msd.msd_Cluster &&
  319.          (dir->de_Msd.msd_Attributes & ATTR_DIR) &&
  320.          (fl->msfl_Msd.msd_Attributes & ATTR_DIR))
  321.         ) {
  322.         /* Found existing lock on file */
  323.         if (fl->msfl_Refcount < 0 || mode == EXCLUSIVE_LOCK) {
  324.         error = ERROR_OBJECT_IN_USE;
  325.         return NULL;
  326.         }
  327.         fl->msfl_Refcount++;
  328.         return fl;
  329.     }
  330.     }
  331.  
  332.     fl = AllocMem((long) sizeof (*fl), MEMF_PUBLIC);
  333.     if (fl == NULL) {
  334.     error = ERROR_NO_FREE_STORE;
  335.     return NULL;
  336.     }
  337.     fl->msfl_Parent = (parentdir != NULL) ? MSDupLock(parentdir) :
  338.                         (struct MSFileLock *) NULL;
  339.  
  340.     fl->msfl_Refcount = (mode == EXCLUSIVE_LOCK) ? -1 : 1;
  341.     fl->msfl_DirSector = dir->de_Sector;
  342.     fl->msfl_DirOffset = dir->de_Offset;
  343.     fl->msfl_Msd = dir->de_Msd;
  344.  
  345.     AddHead((struct List *)&LockList->ll_List, (struct Node *)fl);
  346.  
  347.     return fl;
  348. }
  349.  
  350. /*
  351.  * This routine Locks a file. It first searches it in the directory, then
  352.  * lets the rest of the work be done by MakeLock(). If it encounters an
  353.  * empty slot in the directory, it remembers where, in case we need it. If
  354.  * you clear the MODE_CREATEFILE bit in the mode parameter, we fabricate a
  355.  * new MSFileLock from the empty directory entry. It then becomes the
  356.  * caller's responsibility to MSUnLock() it eventually.
  357.  */
  358.  
  359. struct MSFileLock *
  360. MSLock(parentdir, name, mode)
  361. struct MSFileLock *parentdir;
  362. byte           *name;
  363. ulong        mode;
  364. {
  365.     byte       *sector;
  366.     struct MSFileLock *newlock;
  367.     struct DirEntry *de;
  368.     struct DirEntry sde;
  369.     byte       *nextpart;
  370.     byte        component[L_8 + L_3];    /* Note: not null-terminated */
  371.     int         createit = 0;
  372.     word        freesec;
  373.     word        freeoffset;
  374.  
  375.     de = &sde;
  376.     newlock = NULL;
  377.  
  378.     /*
  379.      * See if we have an absolute path name (starting at the root).
  380.      */
  381.     {
  382.     byte  *colon;
  383.  
  384.     if (colon = strchr(name, ':')) {
  385.         debug(("name == %lx \"%s\"\n", name, name));
  386.         name = colon + 1;
  387.         /*
  388.          * MSH::Command or ::Command?
  389.          */
  390.         if (name[0] == ':') {
  391.         HandleCommand(name);
  392.         error = ERROR_OBJECT_NOT_FOUND;
  393.  
  394.         return NULL;
  395.         }
  396.     }
  397.     }
  398.  
  399.  
  400.     /*
  401.      * Get a copy of the parent dir lock, so we can walk it over the
  402.      * directory tree.
  403.      */
  404. #if HDEBUG
  405.     if (!parentdir)
  406.     debug(("Parentdir == NULL\n"));
  407. #endif
  408.     parentdir = MSDupLock(parentdir);
  409.  
  410.     /*
  411.      * Start with the directory entry of the parent dir.
  412.      */
  413.  
  414. newdir0:
  415.     sde.de_Msd = parentdir->msfl_Msd;
  416.     sde.de_Sector = parentdir->msfl_DirSector;
  417.     sde.de_Offset = parentdir->msfl_DirOffset;
  418. #if HDEBUG
  419.     debug(("pdir %08lx: ", parentdir));
  420.     PrintDirEntry((struct DirEntry *)&parentdir->msfl_Msd);
  421. #endif
  422.  
  423. newdir:
  424.     if (name[0] == '/') {       /* Parentdir */
  425.     name++;
  426.     if (newlock = MSParentDir(parentdir)) {
  427.         MSUnLock(parentdir);
  428.         parentdir = newlock;
  429.         goto newdir0;
  430.     }
  431.     error = ERROR_OBJECT_NOT_FOUND;
  432.     goto some_error;
  433.     } else if (name[0] == '\0') {
  434.     /*
  435.      * Are we at the end of the name? Then we are finished now. This
  436.      * works because sde contains the directory entry of parentdir.
  437.      */
  438.     goto exit;
  439.     } else {            /* Filename or directory part */
  440.     nextpart = ToMSName(component, name);
  441.     debug(("Component: '%.11s'\n", component));
  442.     if (nextpart[0] != '/') {
  443.         nextpart = NULL;
  444. #if ! READONLY
  445.         /*
  446.          * See if we are requested to get an empty spot in the directory
  447.          * if the given name does not exist already. The value of mode is
  448.          * not important until we actually create the filelock.
  449.          */
  450.         if (!(mode & MODE_CREATEFILE)) {
  451.         mode ^= MODE_CREATEFILE;
  452.         createit = 1;
  453.         }
  454. #endif
  455.     } else
  456.         nextpart++;     /* Skip over '/' */
  457.     }
  458.  
  459.     freesec = SEC_EOF;        /* Means none found yet */
  460.  
  461.  
  462.     /*
  463.      * If there is more name, we enter the directory, and here we get the
  464.      * first entry.
  465.      */
  466.  
  467.     sde.de_Sector = DirClusterToSector(sde.de_Msd.msd_Cluster);
  468.     sde.de_Offset = 0;
  469.  
  470.     if ((sector = ReadSec(sde.de_Sector)) == NULL)
  471.     goto some_error;
  472.  
  473.     CopyMem(sector, (char *)&sde.de_Msd, (long) sizeof (struct MsDirEntry));
  474.     OtherEndianMsd(&sde.de_Msd);
  475.     FreeSec(sector);
  476.  
  477.     while (de) {
  478.     switch (CompareNames(&sde.de_Msd, component)) {
  479.     case CMP_FREE_SLOT:
  480.         if (freesec == SEC_EOF) {
  481.         freesec = sde.de_Sector;
  482.         freeoffset = sde.de_Offset;
  483.         }
  484.         /* Fall through */
  485.     case CMP_NOT_EQUAL:
  486.         de = FindNext(&sde, createit);    /* Try next directory
  487.                          * entry */
  488.         continue;
  489.     case CMP_OK_DIR:
  490.         if (name = nextpart) {
  491.         /*
  492.          * We want to keep locks on all directories between each
  493.          * bottom directory and file lock, so we can easily find
  494.          * the parent of a lock. There just seems to be a problem
  495.          * here when we enter the 'subdirectories' . or .. , but
  496.          * that in not so: MakeLock will detect that it has
  497.          * already a lock on those, and NOT make :one/two the
  498.          * parent of :one/two/.. .
  499.          */
  500.         newlock = MakeLock(parentdir, de, SHARED_LOCK);
  501.         MSUnLock(parentdir);
  502.         parentdir = newlock;
  503.         goto newdir;
  504.         }
  505.         goto exit;
  506.     case CMP_OK_FILE:
  507.         if (nextpart) {
  508.         error = ERROR_OBJECT_WRONG_TYPE;
  509.         de = NULL;
  510.         }
  511.         goto exit;
  512.     case CMP_END_OF_DIR:    /* means we will never find it */
  513.         error = ERROR_OBJECT_NOT_FOUND;
  514.         if (freesec == SEC_EOF) {
  515.         freesec = sde.de_Sector;
  516.         freeoffset = sde.de_Offset;
  517.         }
  518.         de = NULL;
  519.         goto exit;
  520.     }
  521.     }
  522.  
  523. exit:
  524.     if (de) {
  525.     newlock = MakeLock(parentdir, &sde, mode);
  526.     } else {
  527.     newlock = NULL;
  528. #if ! READONLY
  529.     if (createit &&     /* Do we want to make it? */
  530.         error == ERROR_OBJECT_NOT_FOUND &&    /* does it not exist yet? */
  531.         nextpart == NULL) { /* do we have the last part of the name */
  532.         if (freesec != SEC_EOF) {    /* is there any room? */
  533.         if (IDDiskState == ID_VALIDATED) {
  534.             error = 0;
  535.             setmem(&sde.de_Msd, sizeof (sde.de_Msd), 0);
  536.             sde.de_Sector = freesec;
  537.             sde.de_Offset = freeoffset;
  538.             /* ToMSName(sde.de_Msd.msd_Name, name); */
  539.             strncpy(sde.de_Msd.msd_Name, component, L_8 + L_3);
  540.             EmptyFileLock = MakeLock(parentdir, &sde, mode);
  541.             WriteFileLock(EmptyFileLock);
  542.         } else
  543.             error = ERROR_DISK_WRITE_PROTECTED;
  544.         } else
  545.         error = ERROR_DISK_FULL;
  546.     }
  547. #endif
  548.     }
  549.  
  550. some_error:
  551.     MSUnLock(parentdir);
  552.  
  553.     return newlock;
  554. }
  555.  
  556. /*
  557.  * This routine DupLocks a file. This simply means incrementing the
  558.  * reference count, if it was not an exclusive Lock.
  559.  */
  560.  
  561. struct MSFileLock *
  562. MSDupLock(fl)
  563. struct MSFileLock *fl;
  564. {
  565.     if (fl == NULL)
  566.     fl = RootLock;
  567.     if (fl->msfl_Refcount <= 0) {
  568.     error = ERROR_OBJECT_IN_USE;
  569.     return NULL;
  570.     } else {
  571.     fl->msfl_Refcount++;
  572.     }
  573.  
  574.     return fl;
  575. }
  576.  
  577. /*
  578.  * This routine DupLocks the parent of a lock, if there is one.
  579.  */
  580.  
  581. struct MSFileLock *
  582. MSParentDir(fl)
  583. struct MSFileLock *fl;
  584. {
  585.     if (fl == NULL) {
  586.     error = ERROR_OBJECT_NOT_FOUND;
  587.     } else if (fl == RootLock) {
  588.     /* Do nothing: return NULL */
  589.     } else if (fl->msfl_Parent)
  590.     return MSDupLock(fl->msfl_Parent);
  591.  
  592.     return NULL;
  593. }
  594.  
  595. /*
  596.  * This routine UnLocks a file.
  597.  */
  598.  
  599. long
  600. MSUnLock(fl)
  601. struct MSFileLock *fl;
  602. {
  603. #if HDEBUG
  604.     debug(("MSUnLock %08lx: ", fl));
  605.     PrintDirEntry((struct DirEntry *)&fl->msfl_Msd);
  606. #endif
  607.  
  608.     if (fl) {
  609.     if (--fl->msfl_Refcount <= 0) {
  610.         struct LockList *list;
  611.  
  612.         if (fl->msfl_Flags & MSFL_DIRTY) {
  613.         WriteFileLock(fl);
  614.         }
  615.  
  616.         list = (struct LockList *) fl->msfl_Node.mln_Pred;
  617.         Remove((struct Node *)fl);
  618.         debug(("Remove()d %08lx\n", fl));
  619.  
  620.         /*
  621.          * We may need to get rid of the LockList if it is empty. This
  622.          * is the current LockList iff we are called from
  623.          * MSDiskRemoved(). Please note that we are not even sure that
  624.          * 'list' really is the list header, therefore the careful
  625.          * test if fl refers to a volume label (root lock) which is
  626.          * finally UnLock()ed. Because of the recursion, we only try to
  627.          * free the LockList iff there is no parent anymore, since
  628.          * otherwise list may be invalid by the time we use it.
  629.          */
  630.         if (fl->msfl_Parent) {
  631.         MSUnLock(fl->msfl_Parent);
  632.         } else {
  633.         if ((fl->msfl_Msd.msd_Attributes & ATTR_VOLUMELABEL) &&
  634.             ((void *) list->ll_List.mlh_Head ==
  635.              (void *) &list->ll_List.mlh_Tail)
  636.             ) {
  637.             FreeLockList(list);
  638.         }
  639.         }
  640.         FreeMem(fl, (long) sizeof (*fl));
  641.     }
  642.     }
  643.     return DOSTRUE;
  644. }
  645.  
  646. /*
  647.  * This is (among other things) the inverse of ToMSName().
  648.  */
  649.  
  650. void
  651. ExamineDirEntry(msd, fib)
  652. struct MsDirEntry *msd;
  653. struct FileInfoBlock *fib;
  654. {
  655. #if HDEBUG
  656.     debug(("+ "));
  657.     PrintDirEntry((struct DirEntry *)msd);
  658. #endif
  659.     /*
  660.      * Special treatment when we examine the root directory
  661.      */
  662.     if (msd->msd_Attributes & ATTR_VOLUMELABEL) {
  663.     strncpy(&fib->fib_FileName[1], msd->msd_Name, L_8 + L_3);
  664.     (void) ZapSpaces(&fib->fib_FileName[2], &fib->fib_FileName[1 + L_8 + L_3]);
  665.     } else {
  666. #if LONGNAMES
  667.     strncpy(&fib->fib_FileName[1], msd->msd_Name, L_8);
  668.     (void) ZapSpaces(&fib->fib_FileName[2], &fib->fib_FileName[1 + L_8]);
  669. #else
  670.     byte  *end,
  671.                *dot;
  672.  
  673.     strncpy(&fib->fib_FileName[1], msd->msd_Name, L_8);
  674.     /* Keep at least one character, even a space, before the dot */
  675.     dot = ZapSpaces(&fib->fib_FileName[2], &fib->fib_FileName[1 + L_8]);
  676.     if (strncmp(msd->msd_Ext, "INF", L_3) == 0) {
  677.         strcpy(dot, ".info");
  678.     } else {
  679.         dot[0] = ' ';
  680.         strncpy(dot + 1, msd->msd_Ext, L_3);
  681.         end = ZapSpaces(dot, dot + 1 + L_3);
  682.         if (end > dot)
  683.         dot[0] = '.';
  684.     }
  685. #endif
  686.     }
  687.     fib->fib_FileName[0] = strlen(&fib->fib_FileName[1]);
  688.  
  689.     fib->fib_EntryType =
  690.     fib->fib_DirEntryType =
  691.     (msd->msd_Attributes & ATTR_DIR) ? FILE_DIR : FILE_FILE;
  692.     fib->fib_Protection = 0;
  693.     if (!(msd->msd_Attributes & ATTR_ARCHIVED))
  694.     fib->fib_Protection |= FIBF_ARCHIVE;
  695.     if (msd->msd_Attributes & ATTR_READONLY)
  696.     fib->fib_Protection |= (FIBF_WRITE | FIBF_DELETE);
  697.     if (msd->msd_Attributes & (ATTR_HIDDEN|ATTR_SYSTEM))
  698.     fib->fib_Protection |= FIBF_HIDDEN;
  699.     fib->fib_Size = msd->msd_Filesize;
  700.     fib->fib_NumBlocks = (msd->msd_Filesize + Disk.bps - 1) / Disk.bps;
  701.     ToDateStamp(&fib->fib_Date, msd->msd_Date, msd->msd_Time);
  702.     fib->fib_Comment[0] = 0;
  703. }
  704.  
  705. /*
  706.  * We remember what we should do when we call ExNext with a lock on
  707.  * a directory (enter or step over it) by a flag in fib_EntryType.
  708.  * Unfortunately, the Commodore (1.3) List and Dir commands expect
  709.  * that fib_EntryType contains the information that the documentation
  710.  * (libraries/dos.h) specifies to be in fib_DirEntryType. Therefore
  711.  * we use the low bit in fib_DiskKey instead. Yech.
  712.  */
  713.  
  714. long
  715. MSExamine(fl, fib)
  716. struct MSFileLock *fl;
  717. struct FileInfoBlock *fib;
  718. {
  719.     if (fl == NULL)
  720.     fl = RootLock;
  721.  
  722.     fib->fib_DiskKey = ((ulong) fl->msfl_DirSector << 16) |
  723.                fl->msfl_DirOffset +
  724.                1;    /* No ExNext called yet */
  725.     ExamineDirEntry(&fl->msfl_Msd, fib);
  726.  
  727.     return DOSTRUE;
  728. }
  729.  
  730. long
  731. MSExNext(fl, fib)
  732. struct MSFileLock *fl;
  733. struct FileInfoBlock *fib;
  734. {
  735.     word        sector = fib->fib_DiskKey >> 16;
  736.     word        offset = (word) fib->fib_DiskKey;
  737.     byte       *buf;
  738.  
  739.     if (fl == NULL)
  740.     fl = RootLock;
  741.  
  742.     if (offset & 1) {
  743.     if (fl->msfl_Msd.msd_Attributes & ATTR_DIR) {
  744.         /* Enter subdirectory */
  745.         sector = DirClusterToSector(fl->msfl_Msd.msd_Cluster);
  746.         offset = 0;
  747.     } else {
  748.         offset--;        /* Remember, it was odd */
  749.         NextDirEntry(§or, &offset);
  750.     }
  751.     } else {
  752. skip:
  753.     NextDirEntry(§or, &offset);
  754.     }
  755.  
  756.     if (sector != SEC_EOF) {
  757.     struct MsDirEntry msd;
  758.  
  759.     if (buf = ReadSec(sector)) {
  760.         msd = *(struct MsDirEntry *) (buf + offset);
  761.         FreeSec(buf);
  762.         if (msd.msd_Name[0] == '\0') {
  763.         goto end;
  764.         }
  765.         if (msd.msd_Name[0] & DIR_DELETED_MASK ||
  766.         msd.msd_Name[0] == '.' ||       /* Hide "." and ".." */
  767.         (msd.msd_Attributes & ATTR_VOLUMELABEL)) {
  768.         goto skip;
  769.         }
  770.         OtherEndianMsd(&msd);    /* Get correct endianness */
  771.         fib->fib_DiskKey = ((ulong) sector << 16) | offset;
  772.         ExamineDirEntry(&msd, fib);
  773.  
  774.         return DOSTRUE;
  775.     }
  776.     }
  777. end:
  778.     error = ERROR_NO_MORE_ENTRIES;
  779.     return DOSFALSE;
  780. }
  781.  
  782. /*
  783.  * Convert AmigaDOS protection bits to messy attribute bits.
  784.  */
  785.  
  786. long
  787. MSSetProtect(parentdir, name, mask)
  788. struct MSFileLock *parentdir;
  789. char       *name;
  790. long       mask;
  791. {
  792.     struct MSFileLock *lock;
  793.  
  794.     if (parentdir == NULL)
  795.     parentdir = RootLock;
  796.  
  797.     lock = MSLock(parentdir, name, EXCLUSIVE_LOCK);
  798.     if (lock) {
  799.     /* Leave other bits as they are */
  800.     lock->msfl_Msd.msd_Attributes &=
  801.         ~(ATTR_READONLY | ATTR_HIDDEN | ATTR_ARCHIVED);
  802.     /* write or delete protected -> READONLY */
  803.     if (mask & (FIBF_WRITE|FIBF_DELETE))
  804.         lock->msfl_Msd.msd_Attributes |= ATTR_READONLY;
  805.     /* hidden -> hidden */
  806.     if (mask & FIBF_HIDDEN)
  807.         lock->msfl_Msd.msd_Attributes |= ATTR_HIDDEN;
  808.     /* archive=0 (default) -> archived=1 (default) */
  809.     if (!(mask & FIBF_ARCHIVE))
  810.         lock->msfl_Msd.msd_Attributes |= ATTR_ARCHIVED;
  811.     WriteFileLock(lock);
  812.     MSUnLock(lock);
  813.     return DOSTRUE;
  814.     }
  815.  
  816.     return DOSFALSE;
  817. }
  818.  
  819. int
  820. CheckLock(lock)
  821. struct MSFileLock *lock;
  822. {
  823.     struct MSFileLock *parent;
  824.  
  825.     if (lock) {
  826.     while (parent = lock->msfl_Parent)
  827.         lock = parent;
  828.     if (lock != RootLock)
  829.         error = ERROR_DEVICE_NOT_MOUNTED;
  830.     }
  831.     return error;
  832. }
  833.  
  834. #if ! READONLY
  835.  
  836. void
  837. WriteDirtyFileLock(fl)
  838. struct MSFileLock *fl;
  839. {
  840.     debug(("WriteDirtyFileLock %08lx\n", fl));
  841.  
  842.     if (fl && (fl->msfl_Flags & MSFL_DIRTY)) {
  843.     WriteFileLock(fl);
  844.     }
  845. }
  846.  
  847. void
  848. WriteFileLock(fl)
  849. struct MSFileLock *fl;
  850. {
  851.     debug(("WriteFileLock %08lx\n", fl));
  852.  
  853.     if (fl && (short) fl->msfl_DirOffset >= 0) {
  854.     byte  *block = ReadSec(fl->msfl_DirSector);
  855.  
  856.     if (block) {
  857.         CopyMem((char *)&fl->msfl_Msd, (char *)block + fl->msfl_DirOffset,
  858.             (long) sizeof (fl->msfl_Msd));
  859.         OtherEndianMsd((struct MsDirEntry *)(block + fl->msfl_DirOffset));
  860.         MarkSecDirty(block);
  861.         FreeSec(block);
  862.         fl->msfl_Flags &= ~MSFL_DIRTY;
  863.     }
  864.     }
  865. }
  866.  
  867. void
  868. UpdateFileLock(fl)
  869. struct MSFileLock *fl;
  870. {
  871.     debug(("UpdateFileLock %08lx\n", fl));
  872.  
  873.     if (fl) {
  874.     struct DateStamp dateStamp;
  875.  
  876.     DateStamp(&dateStamp);
  877.     ToMSDate(&fl->msfl_Msd.msd_Date, &fl->msfl_Msd.msd_Time, &dateStamp);
  878.     /*WriteFileLock(fl);*/
  879.     fl->msfl_Flags |= MSFL_DIRTY;
  880.     }
  881. }
  882.  
  883. void
  884. DirtyFileLock(fl)
  885. struct MSFileLock *fl;
  886. {
  887.     debug(("DirtyFileLock %08lx\n", fl));
  888.  
  889.     if (fl) {
  890.     fl->msfl_Flags |= MSFL_DIRTY;
  891.     }
  892. }
  893.  
  894.  
  895. #endif
  896.  
  897. struct LockList *
  898. NewLockList(cookie)
  899. void           *cookie;
  900. {
  901.     struct LockList *ll;
  902.  
  903.     if (ll = AllocMem((long) sizeof (*ll), MEMF_PUBLIC)) {
  904.     NewList((struct List *)&ll->ll_List);
  905.     ll->ll_Cookie = cookie;
  906.     } else
  907.     error = ERROR_NO_FREE_STORE;
  908.  
  909.     return ll;
  910. }
  911.  
  912. void
  913. FreeLockList(ll)
  914. struct LockList *ll;
  915. {
  916.     debug(("FreeLockList %08lx\n", ll));
  917.  
  918.     if (ll) {
  919.     MayFreeVolNode(ll->ll_Cookie);    /* not too happy about this */
  920.     FreeMem(ll, (long) sizeof (*ll));
  921.     if (ll == LockList)    /* locks on current volume */
  922.         LockList = NULL;
  923.     }
  924. }
  925.